package com.cpms.framework.common.utils;

import com.cpms.framework.common.core.secure.TokenInfo;
import com.cpms.framework.common.enums.GlobalResponseResultEnum;
import com.cpms.framework.common.exception.CheckJwtException;
import com.cpms.framework.common.exception.CheckJwtExpiredException;
import com.google.common.base.Charsets;
import io.jsonwebtoken.*;

import javax.crypto.spec.SecretKeySpec;
import java.security.Key;
import java.util.*;

/**
 * @description: jwt工具类
 * @author: gulang
 * @time: 2021/6/7 10:28
 */
public class CsJwtUtil {
    private static final String DEFAULT_JWT_SECRETKEY = "cpms";
    private static final String JWT_TOKEN_EXPIRE_PROP_KEY = "cpms.jwt-token-expire";
    private static final String JWT_SECRETKEY_PROP_KEY = "cpms.jwt-secretKey";
    /**有效期默认2两小时，单位：小时**/
    private static final long DEFAULT_TOKEN_EXPIRE = 2;
    /**指定签名的时候使用的签名算法**/
    private static final SignatureAlgorithm SIGNATURE_ALGORITHM = SignatureAlgorithm.HS256;
    /**
     *
     * @param claims 根据业务需要保存在token中的信息,比如用户userId、userName
     * @return
     */
    public static TokenInfo createJwt(Map<String, Object> claims){
        return createJwt(claims, getTokenExpire());
    }

    public static long getTokenExpire(){
        long expire = DEFAULT_TOKEN_EXPIRE;
        if(CsStringUtil.isNotBlank(CsPropsUtil.getString(JWT_TOKEN_EXPIRE_PROP_KEY))) {
            expire = Long.parseLong (CsPropsUtil.getString(JWT_TOKEN_EXPIRE_PROP_KEY));
        }
        return expire*3600*1000;
    }

    public static String getBase64Security(){
        String jwtSecretKey = DEFAULT_JWT_SECRETKEY;
        if(CsStringUtil.isNotBlank(CsPropsUtil.getString(JWT_SECRETKEY_PROP_KEY))) {
            jwtSecretKey = CsPropsUtil.getString(JWT_SECRETKEY_PROP_KEY);
        }
       return Base64.getEncoder().encodeToString(jwtSecretKey.getBytes(Charsets.UTF_8));
    }

    /**
     *
     * @param claims 根据业务需要保存在token中的信息,比如用户userId、userName
     * @param expire 自定义token有效时长，单位：毫秒
     * @return
     */
    public static TokenInfo createJwt(Map<String, Object> claims,long expire){
        SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS256;
        long nowMillis = System.currentTimeMillis();
        byte[] apiKeySecretBytes = Base64.getDecoder().decode(getBase64Security());
        Key signingKey = new SecretKeySpec(apiKeySecretBytes, signatureAlgorithm.getJcaName());
        long expMillis = nowMillis + expire;
        Date exp = new Date(expMillis);
        String token = Jwts.builder()
                .setClaims(claims)
                .signWith(SIGNATURE_ALGORITHM, signingKey)
                .setExpiration(exp)
                // 使用Gzip压缩
                .compressWith(CompressionCodecs.GZIP)
                .compact();
        TokenInfo tokenInfo = new TokenInfo();
        tokenInfo.setToken(token);
        tokenInfo.setExpire((int)expire / 1000);
        return tokenInfo;
    }

    /**
     * 解析 token信息
     * @param jsonWebToken
     * @return
     */
    public static Claims parseJwt(String jsonWebToken) {
        try {
            byte[] apiKeySecretBytes = Base64.getDecoder().decode(getBase64Security());
            return Jwts.parser()
                    .setSigningKey(apiKeySecretBytes)
                    .parseClaimsJws(jsonWebToken)
                    .getBody();
        }catch (ExpiredJwtException expired){
            throw new CheckJwtExpiredException(GlobalResponseResultEnum.TOKEN_EXPIRED_ERROR);
        }catch (Exception e){
            throw new CheckJwtException(GlobalResponseResultEnum.TOKEN_CHECK_INVALID_ERROR);
        }
    }
}
